package com.gzhryc.shared_device.oem.code.user.services;

import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.Conditions;
import com.gzhryc.jdbc.JdbcSession;
import com.gzhryc.jdbc.MultiDBTools;
import com.gzhryc.shared_device.base.enums.WalletOperateEnum;
import com.gzhryc.shared_device.base.models.OperateInfo;
import com.gzhryc.shared_device.oem.code.user.dao.UserWalletDao;
import com.gzhryc.shared_device.oem.code.user.dao.db.UserWallet;
import com.gzhryc.shared_device.oem.code.user.services.dto.UserWalletSearch;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

public class UserWalletService {

    static Logger log = Logger.getLogger(UserWalletService.class);

    public static UserWalletService self() {
        return MultiDBTools.getService(UserWalletService.class, true);
    }

    public static UserWalletService self(String jdbcKey) {
        return MultiDBTools.getService(jdbcKey, UserWalletService.class, true);
    }

    UserWalletDao dao;

    public UserWalletService(String jdbcKey) {
        this.dao = new UserWalletDao(jdbcKey);
    }

    public List<UserWallet> findBySearch(UserWalletSearch search, Integer pageNo, Integer pageLimit){
        Conditions conditions = dao.buildConditions(search);
        try {
            return dao.findByCondition(conditions,pageNo,pageLimit);
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return null;
    }

    public List<UserWallet> findJoinByUserId(Long userId){
        if(userId != null){
            Conditions conditions = new Conditions(UserWallet.class);
            conditions.and().is("userId",userId);

            try {
                return dao.findJoinByCondition(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(),e);
            }
        }
        return null;
    }

    public UserWallet getByKeys(Long userId,Long accountGroupId){
        if(userId != null && accountGroupId != null) {
            Conditions conditions = new Conditions(UserWallet.class);
            conditions.and().is("userId",userId);
            conditions.and().is("accountGroupId",accountGroupId);

            try {
                return dao.get(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return null;
    }

    public UserWallet getJoinByKeys(Long userId,Long accountGroupId){
        if(userId != null && accountGroupId != null) {
            Conditions conditions = new Conditions(UserWallet.class);
            conditions.and().is("userId",userId);
            conditions.and().is("accountGroupId",accountGroupId);

            try {
                return dao.getJoin(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return null;
    }

    public Long sumMoney(){
        try {
            return dao.sumMoneyByConditions(new Conditions());
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return 0L;
    }

    public boolean add(UserWallet wallet){
        wallet.setCreateDate(new Date());
        try {
            return dao.insert(wallet) > 0;
        } catch (SQLException e) {
            log.error(e.getMessage(),e);
        }
        return false;
    }

    public boolean addFreezeMoney(Long userId,Long accountGroupId, Long freezeMoney, OperateInfo operateInfo) throws LogicException {
    	if(freezeMoney <= 0) {
    		throw new LogicException("金额必须大于0");
    	}
    	UserWallet wallet = this.getByKeys(userId,accountGroupId);
        if (wallet == null) {
            throw new LogicException("钱包未启用");
        }
        
        Date currentDate = new Date();

        Conditions condition = new Conditions(UserWallet.class);
        condition.and().is("userId", userId);
        condition.and().is("accountGroupId", accountGroupId);
        condition.and().is("freezeMoney", wallet.getFreezeMoney());
        condition.and().is("lastUpdateFMDate", wallet.getLastUpdateFMDate());

        UserWallet walletUpdate = new UserWallet();
        walletUpdate.setFreezeMoney(wallet.getFreezeMoney() + freezeMoney);
        walletUpdate.setLastUpdateFMDate(currentDate);
        
        try {
            if (dao.updateNotNull(walletUpdate, condition) > 0) {
                UserWalletOperateService.self(currentDate).addOperate(wallet.getUserId(),wallet.getAccountGroupId(),
                        WalletOperateEnum.MoneyType.FreezeMoney.index(), WalletOperateEnum.Type.Add.index(), freezeMoney, operateInfo);
                return true;
            }
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        }
        return false;
    }

    public boolean reduceFreezeMoney(Long userId,Long accountGroupId, Long freezeMoney, OperateInfo operateInfo)
            throws LogicException {
    	if(freezeMoney <= 0) {
    		throw new LogicException("金额必须大于0");
    	}
        UserWallet wallet = getByKeys(userId,accountGroupId);
        if (wallet == null) {
            throw new LogicException("钱包未启用");
        }

        // 检查是否够提现金额
        Long surplusMoney = wallet.getFreezeMoney() - freezeMoney;
        if (surplusMoney < 0) {
            throw new LogicException("超过冻结余额");
        } else {
        	Date currentDate = new Date();
        	
            Conditions condition = new Conditions(UserWallet.class);
            condition.and().is("userId", userId);
            condition.and().is("accountGroupId", accountGroupId);
            condition.and().is("freezeMoney", wallet.getFreezeMoney());
            condition.and().is("lastUpdateFMDate", wallet.getLastUpdateFMDate());

            UserWallet walletUpdate = new UserWallet();
            walletUpdate.setFreezeMoney(surplusMoney);
            walletUpdate.setLastUpdateFMDate(currentDate);
            
            try {
                if (dao.updateNotNull(walletUpdate, condition) > 0) {
                    UserWalletOperateService.self(currentDate).addOperate(wallet.getUserId(),wallet.getAccountGroupId(),
                            WalletOperateEnum.MoneyType.FreezeMoney.index(), WalletOperateEnum.Type.Reduce.index(), freezeMoney, operateInfo);
                    return true;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean freezeMoney(Long userId,Long accountGroupId, Long money, OperateInfo operateInfo) throws LogicException {
    	if(money <= 0) {
    		throw new LogicException("金额必须大于0");
    	}
        UserWallet wallet = getByKeys(userId,accountGroupId);
        if (wallet == null) {
            throw new LogicException("钱包未启用");
        }

        // 检查是否够提现金额
        Long surplusMoney = wallet.getWithdrawalMoney() - money;
        if (surplusMoney < 0) {
            throw new LogicException("超过钱包余额");
        } else {
        	Date currentDate = new Date();
        	
            Conditions condition = new Conditions(UserWallet.class);
            condition.and().is("userId", userId);
            condition.and().is("accountGroupId", accountGroupId);
            condition.and().is("withdrawalMoney", wallet.getWithdrawalMoney());
            condition.and().is("freezeMoney", wallet.getFreezeMoney());
            condition.and().is("lastUpdateWMDate", wallet.getLastUpdateWMDate());
            condition.and().is("lastUpdateFMDate", wallet.getLastUpdateFMDate());

            UserWallet walletUpdate = new UserWallet();
            walletUpdate.setWithdrawalMoney(surplusMoney);
            walletUpdate.setFreezeMoney(wallet.getFreezeMoney() + money);
            walletUpdate.setLastUpdateWMDate(currentDate);
            walletUpdate.setLastUpdateFMDate(currentDate);
            
            try {
                if(dao.updateNotNull(walletUpdate, condition) > 0){
                    UserWalletOperateService.self(currentDate).addOperate(wallet.getUserId(), wallet.getAccountGroupId(),
                            WalletOperateEnum.MoneyType.FreezeMoney.index(), WalletOperateEnum.Type.Add.index(), money, operateInfo);
                    UserWalletOperateService.self(currentDate).addOperate(wallet.getUserId(), wallet.getAccountGroupId(),
                            WalletOperateEnum.MoneyType.WithdrawalMoney.index(), WalletOperateEnum.Type.Reduce.index(), money, operateInfo);
                    return true;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean unfreezeMoney(Long userId,Long accountGroupId, Long money, OperateInfo operateInfo) throws LogicException {
    	if(money <= 0) {
    		throw new LogicException("金额必须大于0");
    	}
        UserWallet wallet = getByKeys(userId,accountGroupId);
        if (wallet == null) {
            throw new LogicException("钱包未启用");
        }

        // 检查是否够提现金额
        Long surplusMoney = wallet.getFreezeMoney() - money;
        if (surplusMoney < 0) {
            throw new LogicException("超过冻结余额");
        } else {
        	Date currentDate = new Date();
        	
            Conditions condition = new Conditions(UserWallet.class);
            condition.and().is("userId", userId);
            condition.and().is("accountGroupId", accountGroupId);
            condition.and().is("withdrawalMoney", wallet.getWithdrawalMoney());
            condition.and().is("freezeMoney", wallet.getFreezeMoney());
            condition.and().is("lastUpdateWMDate", wallet.getLastUpdateWMDate());
            condition.and().is("lastUpdateFMDate", wallet.getLastUpdateFMDate());

            UserWallet walletUpdate = new UserWallet();
            walletUpdate.setWithdrawalMoney(wallet.getWithdrawalMoney() + money); // 增加余额
            walletUpdate.setFreezeMoney(surplusMoney);
            walletUpdate.setLastUpdateWMDate(currentDate);
            walletUpdate.setLastUpdateFMDate(currentDate);
            
            try {
                if(dao.updateNotNull(walletUpdate, condition) > 0){
                    UserWalletOperateService.self(currentDate).addOperate(wallet.getUserId(), wallet.getAccountGroupId(),
                            WalletOperateEnum.MoneyType.FreezeMoney.index(), WalletOperateEnum.Type.Reduce.index(), money, operateInfo);
                    UserWalletOperateService.self(currentDate).addOperate(wallet.getUserId(), wallet.getAccountGroupId(),
                            WalletOperateEnum.MoneyType.WithdrawalMoney.index(), WalletOperateEnum.Type.Add.index(), money, operateInfo);
                    return true;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean reduceMoney(Long userId,Long accountGroupId, Long money, OperateInfo operateInfo) throws LogicException {
    	if(money <= 0) {
    		throw new LogicException("金额必须大于0");
    	}
        UserWallet wallet = this.getByKeys(userId,accountGroupId);
        if (wallet == null) {
            throw new LogicException("钱包未启用");
        }
        // 检查金额是否够扣除
        if (wallet.getMoney() < money) {
            throw new LogicException("超过钱包余额");
        }else {
        	Date currentDate = new Date();
        	
            Conditions condition = new Conditions(UserWallet.class);
            condition.and().is("userId", userId);
            condition.and().is("accountGroupId", accountGroupId);
            condition.and().is("money", wallet.getMoney());
            condition.and().is("lastUpdateDate", wallet.getLastUpdateDate());

            UserWallet walletUpdate = new UserWallet();
            walletUpdate.setMoney(wallet.getMoney() - money);
            walletUpdate.setLastUpdateDate(currentDate);
            
            try {
                if (dao.updateNotNull(walletUpdate, condition) > 0) {
                    UserWalletOperateService.self(currentDate).addOperate(wallet.getUserId(),wallet.getAccountGroupId(),
                            WalletOperateEnum.MoneyType.Money.index(), WalletOperateEnum.Type.Reduce.index(), money, operateInfo);
                    return true;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean addMoney(Long userId,Long accountGroupId, Long money, OperateInfo operateInfo) throws LogicException {
    	if(money <= 0) {
    		throw new LogicException("金额必须大于0");
    	}
        UserWallet wallet = this.getByKeys(userId,accountGroupId);
        if (wallet == null) {
            throw new LogicException("钱包未启用");
        }
        
        Date currentDate = new Date();

        Conditions condition = new Conditions(UserWallet.class);
        condition.and().is("userId", userId);
        condition.and().is("accountGroupId", accountGroupId);
        condition.and().is("money", wallet.getMoney());
        condition.and().is("lastUpdateDate", wallet.getLastUpdateDate());

        UserWallet walletUpdate = new UserWallet();
        walletUpdate.setMoney(wallet.getMoney() + money);
        walletUpdate.setLastUpdateDate(currentDate);
        try {
            if (dao.updateNotNull(walletUpdate, condition) > 0) {
                UserWalletOperateService.self(currentDate).addOperate(wallet.getUserId(),wallet.getAccountGroupId(),
                        WalletOperateEnum.MoneyType.Money.index(), WalletOperateEnum.Type.Add.index(), money, operateInfo);
                return true;
            }
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        }
        return false;
    }

    public boolean addWithdrawalMoney(Long userId,Long accountGroupId, Long money, OperateInfo operateInfo) throws LogicException {
    	if(money <= 0) {
    		throw new LogicException("金额必须大于0");
    	}
        UserWallet wallet = this.getByKeys(userId,accountGroupId);
        if (wallet == null) {
            throw new LogicException("钱包未启用");
        }
        
        Date currentDate = new Date();

        Conditions condition = new Conditions(UserWallet.class);
        condition.and().is("userId", userId);
        condition.and().is("accountGroupId", accountGroupId);
        condition.and().is("withdrawalMoney", wallet.getWithdrawalMoney());
        condition.and().is("lastUpdateWMDate", wallet.getLastUpdateWMDate());

        UserWallet walletUpdate = new UserWallet();
        walletUpdate.setWithdrawalMoney(wallet.getWithdrawalMoney() + money);
        walletUpdate.setLastUpdateWMDate(currentDate);

        try {
            if (dao.updateNotNull(walletUpdate, condition) > 0) {
                UserWalletOperateService.self(currentDate).addOperate(wallet.getUserId(),wallet.getAccountGroupId(),
                        WalletOperateEnum.MoneyType.WithdrawalMoney.index(), WalletOperateEnum.Type.Add.index(), money, operateInfo);
                return true;
            }
        } catch (SQLException e) {
            log.error(e.getMessage(), e);
        }
        return false;
    }

    public boolean transferMoneyToWithdrawal(Long userId,Long accountGroupId, Long money, OperateInfo operateInfo) throws LogicException {
    	if(money <= 0) {
    		throw new LogicException("金额必须大于0");
    	}
        UserWallet wallet = this.getByKeys(userId,accountGroupId);
        if (wallet == null) {
            throw new LogicException("钱包未启用");
        }

        // 检查金额是否够扣除
        if (wallet.getMoney() < money) {
            throw new LogicException("超过钱包余额");
        }else {
        	Date currentDate = new Date();
        	
            Conditions condition = new Conditions(UserWallet.class);
            condition.and().is("userId", userId);
            condition.and().is("accountGroupId", accountGroupId);
            condition.and().is("money", wallet.getMoney());
            condition.and().is("withdrawalMoney", wallet.getWithdrawalMoney());
            condition.and().is("lastUpdateWMDate", wallet.getLastUpdateWMDate());

            UserWallet walletUpdate = new UserWallet();
            walletUpdate.setMoney(wallet.getMoney() - money);
            walletUpdate.setWithdrawalMoney(wallet.getWithdrawalMoney() + money);
            walletUpdate.setLastUpdateDate(currentDate);
            walletUpdate.setLastUpdateWMDate(currentDate);

            try {
                if (dao.updateNotNull(walletUpdate, condition) > 0) {
                    UserWalletOperateService.self(currentDate).addOperate(wallet.getUserId(),wallet.getAccountGroupId(),
                            WalletOperateEnum.MoneyType.Money.index(), WalletOperateEnum.Type.Transfer.index(), money, operateInfo);
                    return true;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }
    
    public boolean restitutionToMoney(Long userId,Long accountGroupId, Long money, OperateInfo operateInfo) throws LogicException {
    	if(money <= 0) {
    		throw new LogicException("金额必须大于0");
    	}
        UserWallet wallet = this.getByKeys(userId,accountGroupId);
        if (wallet == null) {
            throw new LogicException("钱包未启用");
        }

        // 检查金额是否够扣除
        if (wallet.getWithdrawalMoney() < money) {
            throw new LogicException("超过钱包提现金额");
        }else {
        	Date currentDate = new Date();
        	
            Conditions condition = new Conditions(UserWallet.class);
            condition.and().is("userId", userId);
            condition.and().is("accountGroupId", accountGroupId);
            condition.and().is("money", wallet.getMoney());
            condition.and().is("withdrawalMoney", wallet.getWithdrawalMoney());
            condition.and().is("lastUpdateDate", wallet.getLastUpdateDate());

            UserWallet walletUpdate = new UserWallet();
            walletUpdate.setMoney(wallet.getMoney() + money);
            walletUpdate.setWithdrawalMoney(wallet.getWithdrawalMoney() - money);
            walletUpdate.setLastUpdateDate(currentDate);
            walletUpdate.setLastUpdateWMDate(currentDate);

            try {
                if (dao.updateNotNull(walletUpdate, condition) > 0) {
                    UserWalletOperateService.self(currentDate).addOperate(wallet.getUserId(),wallet.getAccountGroupId(),
                            WalletOperateEnum.MoneyType.Money.index(), WalletOperateEnum.Type.Restitution.index(), money, operateInfo);
                    return true;
                }
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
            }
        }
        return false;
    }

    public boolean deleteByUserId(Long userId) throws LogicException {
        if(userId != null) {
            List<UserWallet> walletList = null;
            Conditions conditions = new Conditions(UserWallet.class);
            conditions.and().is("userId",userId);
            
            try {
                walletList = dao.findByCondition(conditions);
            } catch (SQLException e) {
                log.error(e.getMessage(), e);
                return false;
            }

            if(walletList != null && walletList.size() > 0){
                for(UserWallet wallet : walletList){
                    if (wallet.getMoney() > 0 || wallet.getFreezeMoney() > 0) {
                        throw new LogicException("钱包还有余额，不允许删除");
                    }
                }

                JdbcSession.begin();
                try {
                    if (dao.deleteByCondition(conditions) > 0) {
                        if (UserWalletOperateService.self(new Date()).deleteByUserId(userId)) {
                            JdbcSession.commit();
                            return true;
                        }
                    }
                } catch (SQLException e) {
                    log.error(e.getMessage(), e);
                } finally {
                    JdbcSession.end();
                }
            }else{
                return true;
            }
        }
        return false;
    }
}
